﻿using System;
using System.Collections.Generic;
using System.Composition;
using System.Composition.Convention;
using System.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;
using Ant.ICommon.Utilities;
using Ant.Interface.Log;
using Ant.Interface.Mef.Model;
using Ant.Interface.Mef.Model.Catalogs;
using Ant.Interface.Mef.Model.Catalogs.CatalogType;
using Ant.Interface.Mef.Model.Mappings;

namespace Ant.Interface.Mef.Controller
{
    /// <summary>
    /// 插件控制器。
    /// </summary>
    internal class MefController : IMefController
    {
        #region "Field"

        /// <summary>
        /// 目录。
        /// </summary>
        private ContainerConfiguration _containerConfiguration = new ContainerConfiguration();

        /// <summary>
        /// 组成容器。
        /// </summary>
        private CompositionHost _container;

        /// <summary>
        /// 组件映射信息。
        /// </summary>
        private MefMappings _plugInMappings;

        /// <summary>
        /// 公约。
        /// </summary>
        private ConventionBuilder _conventionBuilder = new ConventionBuilder();

        #endregion "Field"

        #region "IMefController Member"

        #region "Load"

        public void LoadParts(string configFilePath)
        {
            MefsConfig plugInsConfig;

            try
            {
                plugInsConfig = XmlHelper.DeserializeXml<MefsConfig>(configFilePath);
            }
            catch (Exception e)
            {
                SimpleLog.Info(string.Format("加载插件集合出错详细信息：{0}", e.Message));
                return;
            }

            if (plugInsConfig == null || Is.Empty(plugInsConfig.ConfigItems))
                return;

            var plugInConfigItems = plugInsConfig.ConfigItems.Where(item => item.Enabled);

            foreach (var item in plugInConfigItems)
            {
                //                try
                //                {
                LoadCatalogs(item.CatalogsPath);

                //                }
                //                catch
                //                {
                //                }
            }
        }

        public void LoadCatalogs(string configFilePath)
        {
            if (string.IsNullOrWhiteSpace(configFilePath))
                return;
            if (!File.Exists(configFilePath))
            {
                SimpleLog.Info(string.Format("找不到目录配置文件：{0}", configFilePath));
                return;
            }

            CatalogConfigs catalogConfigs;

            try
            {
                catalogConfigs = XmlHelper.DeserializeXml<CatalogConfigs>(configFilePath);
            }
            catch (Exception e)
            {
                SimpleLog.Info(string.Format("加载目录集合出错详细信息：{0}", e.Message));
                return;
            }

            LoadCatalogConfig(catalogConfigs);
        }

        public void LoadMappings(string configFilePath)
        {
            try
            {
                _plugInMappings = XmlHelper.DeserializeXml<MefMappings>(configFilePath);
            }
            catch (Exception e)
            {
                _plugInMappings = new MefMappings
                                      {
                                          Mappings = new List<MefMappingItem>()
                                      };
                SimpleLog.Info(string.Format("加载插件映射出错详细信息：{0}", e.Message));
            }
        }

        public void LoadParts(Assembly assembly)
        {
            _containerConfiguration.WithAssembly(assembly);
        }

        public void LoadParts(IEnumerable<Assembly> assemblies)
        {
            _containerConfiguration.WithAssemblies(assemblies);
        }

        public void LoadPart(Type partType)
        {
            _containerConfiguration.WithPart(partType);
        }

        public void LoadPart(Type partType, AttributedModelProvider conventions)
        {
            _containerConfiguration.WithPart(partType, conventions);
        }

        public void LoadPart<T>() where T : IDependency
        {
            _containerConfiguration.WithPart<T>();
        }

        public void LoadPart<T>(AttributedModelProvider conventions) where T : IDependency
        {
            _containerConfiguration.WithPart<T>(conventions);
        }

        public void LoadParts(IEnumerable<Type> partTypes)
        {
            _containerConfiguration.WithParts(partTypes);
        }

        public void LoadParts(IEnumerable<Type> partTypes, AttributedModelProvider conventions)
        {
            _containerConfiguration.WithParts(partTypes, conventions);
        }

        public void LoadParts(params Type[] partTypes)
        {
            _containerConfiguration.WithParts(partTypes);
        }

        #endregion "Load"

        #region "Get"

        public T Get<T>() where T : IDependency
        {
            var contractName = GetContractName<T>();
            return !string.IsNullOrWhiteSpace(contractName) ? Get<T>(contractName) : _container.GetExport<T>();
        }

        public T Get<T>(string contractName) where T : IDependency
        {
            return _container.GetExport<T>(contractName);
        }

        public object Get(Type plugInType)
        {
            return _container.GetExport(plugInType);
        }

        public object Get(Type plugInType, string contractName)
        {
            return _container.GetExport(plugInType, contractName);
        }

        public IEnumerable<T> Gets<T>() where T : IDependency
        {
            return _container.GetExports<T>();
        }

        public IEnumerable<T> Gets<T>(string contractName) where T : IDependency
        {
            return _container.GetExports<T>(contractName);
        }

        public IEnumerable<object> Gets(Type plugInType)
        {
            return _container.GetExports(plugInType);
        }

        public IEnumerable<object> Gets(Type plugInType, string contractName)
        {
            return _container.GetExports(plugInType, contractName);
        }

        public bool TryGet<T>(out T plugIn) where T : IDependency
        {
            return _container.TryGetExport(out plugIn);
        }

        public bool TryGet<T>(string contractName, out T plugIn) where T : IDependency
        {
            return _container.TryGetExport(contractName, out plugIn);
        }

        public bool TryGet(Type plugInType, out object plugIn)
        {
            return _container.TryGetExport(plugInType, out plugIn);
        }

        public bool TryGet(Type plugInType, string contractName, out object plugIn)
        {
            return _container.TryGetExport(plugInType, contractName, out plugIn);
        }

        #endregion "Get"

        public void CreateContainer()
        {
            try
            {
                _containerConfiguration.WithDefaultConventions(ConventionBuilder);
            }
            catch { }
            _container = _containerConfiguration.CreateContainer();
            _container.Dispose();
        }

        #endregion "IMefController Member"

        #region "Private Method"

        /// <summary>
        /// 加载组件。
        /// </summary>
        /// <param name="catalogConfigs">目录配置枚举器。</param>
        private void LoadCatalogConfig(CatalogConfigs catalogConfigs)
        {
            if (catalogConfigs == null)
                return;

            LoadCatalogConfig(catalogConfigs.Catalogs);
        }

        /// <summary>
        /// 加载组件。
        /// </summary>
        /// <param name="catalogConfigs">目录配置枚举器。</param>
        private void LoadCatalogConfig(IEnumerable<CatalogConfigBase> catalogConfigs)
        {
            if (Is.Empty(catalogConfigs))
                return;

            var catalogs = catalogConfigs.Where(catalog => catalog.ComposablePart != null);

            foreach (var catalogConfig in catalogs)
            {
                try
                {
                    switch (catalogConfig.CatalogType)
                    {
                        case CatalogType.AssemblyCatalog:
                        case CatalogType.DirectoryCatalog:
                            var assemblys = catalogConfig.ComposablePart as IEnumerable<Assembly>;
                            if (!Is.Empty(assemblys))
                            {
                                _containerConfiguration.WithAssemblies(assemblys);
                            }
                            break;

                        case CatalogType.TypeCatalog:
                            var type = catalogConfig.ComposablePart as Type;
                            if (type != null)
                            {
                                _containerConfiguration.WithPart(type);
                            }
                            break;
                    }
                }
                catch (Exception e)
                {
                    SimpleLog.Info(string.Format("加载目录出错详细信息：{0}", e.Message));
                }
            }
        }

        /// <summary>
        /// 获取契约名称。
        /// </summary>
        /// <typeparam name="T">类型。</typeparam>
        /// <returns>契约名称，找不到则为Null。</returns>
        private string GetContractName<T>()
        {
            var mapping = _plugInMappings.Mappings.SingleOrDefault(plugIn => string.Equals(plugIn.TypeName, typeof(T).FullName));
            return mapping == null ? null : mapping.ContractName;
        }

        #endregion "Private Method"

        /// <summary>
        ///  约束制造器。
        /// </summary>
        public ConventionBuilder ConventionBuilder { get { return _conventionBuilder; } }

        public void SatisfyImports(params object[] objectWithLooseImports)
        {
            if (objectWithLooseImports == null)
                return;

            foreach (var objectWithLooseImport in objectWithLooseImports)
            {
                _container.SatisfyImports(objectWithLooseImport);
            }
        }

        public void Dispose()
        {
            if (_container != null)
            {
                _container.Dispose();
                _container = null;
            }
            _containerConfiguration = null;
            _conventionBuilder = null;
            _plugInMappings = null;
        }
    }
}